﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace FluentETL.Impl
{
    public class ObjectSource: ISource, IFieldNames
    {
        private IEnumerable DataSource { get; set; }
        private IDictionary<string, PropertyInfo> _cachedProperties;

        public ObjectSource()
        {
        }

        public ObjectSource From<T>(IEnumerable<T> dataSource)
        {
            this.DataSource = dataSource;
            _cachedProperties = GetProperties(typeof(T));
            return this;
        }

        public ObjectSource From(IEnumerable dataSource)
        {
            this.DataSource = dataSource;
            _cachedProperties = GetProperties(this.DataSource.GetType());
            return this;
        }

        public IEnumerable<string> GetFieldNames()
        {
            if (_cachedProperties == null)
                throw new InvalidOperationException("Not enough information to determine field names.");
            return from p in _cachedProperties.Keys
                   select p;
        }

        void ISource.InTransformContext(ITransform t, Action action)
        {
            action();
        }

        IEnumerable<IRow> ISource.Rows
        {
            get
            {
                if (this.DataSource == null)
                    throw new InvalidOperationException("No data source set.");
                foreach (object obj in this.DataSource)
                {
                    var props = _cachedProperties;
                    if (props == null)
                        props = GetProperties(obj.GetType());
                    IRow r = new ObjectRow(obj, props);
                    yield return r;
                }
            }
        }

        private IDictionary<string, PropertyInfo> GetProperties(Type t)
        {
            IDictionary<string, PropertyInfo> dict = new Dictionary<string, PropertyInfo>();
            PropertyInfo[] props = t.GetProperties();
            if (props == null)
                return null;
            foreach (PropertyInfo p in props)
            {
                if (p.CanRead)
                {
                    ParameterInfo[] indexParams = p.GetIndexParameters();
                    if (indexParams == null || indexParams.Length == 0)
                        dict[p.Name] = p;
                }
            }
            return dict;
        }
    }
}